package com.nstar.sinaweibo.components
{
/**
组件名称：列表组件
组件说明：微博、评论、收藏等等数据列表
开发时间：2010.12.8
开发人员: Jonny
*/	
	import com.nstar.sinaweibo.controller.ClientEvent;
	import com.nstar.sinaweibo.controller.MainController;
	import com.nstar.sinaweibo.manager.MsgManager;
	import com.nstar.sinaweibo.model.PageVO;
	import com.nstar.sinaweibo.model.Utils;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.ui.Keyboard;
	
	import gs.TweenLite;
	
	import mx.binding.utils.BindingUtils;
	import mx.collections.ArrayCollection;
	import mx.containers.Canvas;
	import mx.containers.VBox;
	import mx.controls.Alert;
	import mx.core.IFactory;
	import mx.core.mx_internal;
	import mx.events.CollectionEvent;
	import mx.events.FlexEvent;
	import mx.events.ScrollEvent;
	
	use namespace mx_internal;
	

	public class CustomList extends Canvas
	{
		public static const UPDATE_ALL	:uint = 0;//全部，更新dataProvider
		public static const UPDATE_ONE	:uint = 1;//更新一个，来了一个新消息时
		public static const UPDATE_LIST	:uint = 2;//更新一个列表，来了N个新消息时
		public static const REMOVE_ONE	:uint = 3;//删除一个
		public static const APPEND_LIST :uint = 4;//追加一个列表，翻页时
		
		public static const SCROLL_SIZE :uint = 70;//鼠标滚动时的步长
		public static const THUMB_MIN_HEIGHT: int = 80;
		
		private var _dataProvider:ArrayCollection;
		private var _controller:MainController;	
		private var _itemRenderer:IFactory;
		
		private var updateType:int = -1;//更新类型，见上面常量说明
		
		
		private var container:VBox;
		private var morePanel:MorePanel;
		private var selectedRect:Canvas;//鼠标当前经过的微博时，用以作为背景
		
		private var _pageVO:PageVO = new PageVO();//分页对象
		
		private var _isSentRequest:Boolean = false;//是否已发送获取更多数据的请求
		
		private var _selectedItem:Object;
		
		private var useZebraCrossing:Boolean = false;//使用斑马线分割
		
		public var maxCount:int = 40;//列表可容纳的最大消息数目
		public var getCount:int = 20;//每次从服务器获取的微博数量
		
		public function CustomList()
		{
			super();
			
			verticalScrollPolicy = "on";
			horizontalScrollPolicy = "off";
			this.verticalLineScrollSize = 40;
			this.styleName = "customList";
			
			this.addEventListener(FlexEvent.CREATION_COMPLETE,init);
		}
		
		private function init(event:FlexEvent):void{
			//this.addEventListener(MouseEvent.MOUSE_WHEEL,scrollHandler);
			//this.addEventListener(ScrollEvent.SCROLL,scrollHandler);
			this.addEventListener(ClientEvent.EXPAND_LIST,expandListHandler);
			this.addEventListener(KeyboardEvent.KEY_DOWN,shortCutsHandler);
		}
		
		override protected function createChildren():void
		{
			super.createChildren();
			
			selectedRect = new Canvas();
			selectedRect.alpha = 0;
			selectedRect.styleName = "selectedRectangle";
			
			addChild(selectedRect);
			
			container = new VBox();
			container.addEventListener(Event.ADDED,addedHandler);
			container.styleName = "customListContainer";
			container.percentWidth = 100;
			addChild(container);
			
			morePanel = new MorePanel();
			morePanel.visible = morePanel.includeInLayout = false;
			addChild(morePanel);
		}
		
		private function addedHandler(event:Event):void{
		}
		
		//开始更新视图
		override protected function commitProperties():void
		{
			super.commitProperties();
		}
		
		public function set controller(value:MainController):void
		{
			_controller = value;
			if(!_controller)
			{
				return;
			}
		}
		
		//绑定dataProvider到controller指定属性
		public function bindDataProvider(property:String):void{
			if(_controller.mainData.hasOwnProperty(property)){
				BindingUtils.bindProperty(this, "dataProvider", _controller.mainData, property);
			}else{
				Alert.show("no such property : "+property);
			}
		}
		
		public function set itemRenderer(value:IFactory):void
		{
			_itemRenderer = value;
		}
		
		public function set dataProvider(value:ArrayCollection):void
		{
			if(_dataProvider)
			{
				_dataProvider.removeEventListener(CollectionEvent.COLLECTION_CHANGE, onCollectionChange);
			}
			_dataProvider = value;
			if(_dataProvider)
			{
				_dataProvider.addEventListener(CollectionEvent.COLLECTION_CHANGE, onCollectionChange);
			}
			
			needUpdated(UPDATE_ALL);
		}
		
		public function get dataProvider():ArrayCollection{
			return _dataProvider;
		}
			
		
		private function onCollectionChange(event:CollectionEvent):void
		{
			trace("Collection Change!!!"+event.items.length);
			
		}
		
		//更新全部列表
		private function updateAll():void
		{
			trace("update all,count="+_dataProvider.length);
			if(!container)
			{
				return;
			}
			container.removeAllChildren();
			for each(var data:Object in _dataProvider)
			{
				addInstance(data);
			}
			trace("update all over");
		}
		
		//更新一条
		private function updateOne():void{
			var item:Object = _dataProvider.getItemAt(0);
			addInstanceAt(item,0);
			
			removeLast();
		}
		
		//更新一列消息，根据updateCount属性判断更新的条数
		private function updateList():void{
			//获取列表中的前updateCount条消息
			var list:Array = _dataProvider.toArray().slice(0,updateCount);
			var idx:int = 0;
			for each(var item:Object in list){
				addInstanceAt(item,idx);
				idx++;
			}
			
			removeLast();
		}
		
		//追加一组消息到列表末尾
		private function appendList():void{
			//取新消息的范围
			var list:Array = _dataProvider.toArray().slice(_dataProvider.length-updateCount,_dataProvider.length);
			var idx:int = 0;
			for each(var item:Object in list){
				addInstance(item);
				idx++;
			}
			
			//停止更多面板的提示，并复位
			resetMorePanel();
		}
		
		
		//添加一条实例消息到列表结尾
		private function addInstance(data:Object):void{
			var obj:Object = _itemRenderer.newInstance();
			obj.addEventListener(MouseEvent.ROLL_OVER,readHandler);//更新新消息为已读
			obj.controller = _controller;
			obj.data = data;
			container.addChild(obj as DisplayObject);
		}
		
		//添加一条实例消息到列表里指定位置
		private function addInstanceAt(data:Object,index:int):void{
			var obj:Object = _itemRenderer.newInstance();
			obj.addEventListener(MouseEvent.ROLL_OVER,readHandler);//更新新消息为已读
			
			obj.controller = _controller;
			obj.data = data;
			container.addChildAt(obj as DisplayObject,index);
		}
		
		
		//更新新消息为已读
		private function readHandler(event:MouseEvent):void{
			_selectedItem = event.currentTarget;
			switch(event.type){
				case MouseEvent.ROLL_OVER:
					if(_selectedItem.read==false){
						_selectedItem.read = true;
						//刷新列表背景色
						this.updateBackground();
						//通知消息数已经更新
						this.dispatchEvent(new ClientEvent(ClientEvent.MESSAGE_READ,true));
					}
					var p:Point = _controller.getAppPosition();//取得App的位置
					TweenLite.to(selectedRect,0.5,
						{x:_selectedItem.x,y:_selectedItem.y+container.getStyle("top"),
						 width:_selectedItem.width+20,height:_selectedItem.height,alpha:1});
					break;
				case MouseEvent.ROLL_OUT:
					break;
			}
		}
		
		private function getVSpace():Number{
			return container.getStyle("top") + container.getStyle("paddingTop");
		}
		
		//删除指定索引位置的实例消息
		private function removeInstanceAt(index:int):void{
			container.removeChildAt(index);
			TweenLite.to(selectedRect,0.5,{height:0,alpha:0});
		}
		
		public function set selectedIndex(value:int):void{}
		
		public function get selectedIndex():int{
			return -1;
		}
		
		public function set selectedItem(value:Object):void{
			this._selectedItem = value;
		}
		
		public function get selectedItem():Object{
			return this._selectedItem;
		}
		
		//更新列表中微博的背景色，以斑马条纹形式在微博与微博之间区分
		public function updateBackground():void{
			if(useZebraCrossing){
				var idx:int = 0;
				//var color1:uint = CSSParser.getStyle(".listColor1","backgroundColor");
				//var color2:uint = CSSParser.getStyle(".listColor2","backgroundColor");
				for each(var item:Object in container.getChildren()){
					//如果是新消息，则不处理
					if(Utils.isUnReadColor(item.getStyle("backgroundColor"))) continue;
					if(idx%2==0){
						//只改变背景色，这样速度会快些[设置styleName速度会比较慢]
						//item.setStyle("backgroundColor",color1);
						item.styleName = "listColor1";
					}else{
						//item.setStyle("backgroundColor",color2);
						item.styleName = "listColor2";
					}
					idx++;
				}
			}
		}
		
		//更新ids中的ID为新消息背景样式
		public function updateNew(count:uint):void{
			/** 真实ID比较
			var ids:String ="";
			for each(var item:Object in newsList){
				ids += item.id+",";
			}
			
			for each(var item:Object in container.getChildren()){
				if(ids.indexOf(item.ID)!=-1){
					item.setAsNewMessage();
				}
			}*/
			//直接根据数量来设置前N个为新消息,因为在切换消息时不好确定之前新增的消息中哪些是新的
			trace("update count="+count);
			for (var i:int = 0;i<count;i++){
				if(container.getChildAt(i)){
					MsgManager(container.getChildAt(i)).setAsNewMessage();
				}
				
			}
		}
		
		public function set isSentRequest(value:Boolean):void{
			this._isSentRequest = value;
		}
		
		public function get isSentRequest():Boolean{
			return this._isSentRequest;
		}
		
		private function mouseWheelHandler(event:MouseEvent):void{
			event.preventDefault();
		}
		
		//鼠标滚轮/拖动滚动条的控制
		var np:Number = 0;
		private function scrollHandler(event:Event):void{
			//计算缓动效果的滚动条下一个位置
	       	var start:Number = this.verticalScrollPosition;
	       	var end:Number = start;
	       	
			//需要等待下一次获取数据后才能再次发送请求
			getMoreHandler(start,np);
				       	
	       	if(start>np){//向下滚轮
	       		//trace("DOWN!!!!");
	       		end += SCROLL_SIZE;
	       		if(start>=this.maxVerticalScrollPosition){
	       			start = this.maxVerticalScrollPosition;
	       			end = start;
	       		}
	       	}else{//向上滚轮
	       		//trace("UP!!!!");
	       		end -= SCROLL_SIZE;
	       		if(start<=0){
	       			start = 0;
	       			end = 0;
	       		}
	       	}
	       	
	       	np = this.verticalScrollPosition;//保留前面的值
	       	
	       	TweenLite.to(this,1,{verticalScrollPosition:end});
		}
		
		//触发获取更多数据
		private function getMoreHandler(start:int,np:int):void{
			if(_isSentRequest==false && start>np &&
				this.verticalScrollPosition >= this.maxVerticalScrollPosition-5 &&
				items.length>=getCount){
				_isSentRequest = true;
				//滚动条位置设置在最下面，以显示当前正在加载数据的更多面板
				this.verticalScrollPosition = this.maxVerticalScrollPosition;
				pageVO.next();//下一页
				//通知需要获取更多数据
				this.dispatchEvent(new ClientEvent(ClientEvent.REQUEST_GET_MORE_MSG,true,pageVO));
			}

		}
		
		
		public function set pageVO(value:PageVO):void{
			this._pageVO = value;
		}
		
		public function get pageVO():PageVO{
			return this._pageVO;
		}
		
		//复位分页
		public function resetPage():void{
			_controller.isPaging = false;
			_pageVO.reset();
			//清除列表中的数据，只保留20条（每次从服务器取微博的数量）
			if(items.length>getCount){
				removeLastMsgs(items.length - getCount);
			}
		}
		
		//重新设置分页步长
		public function resetStep(page:int,step:int):void{
			_pageVO.page = page;
			_pageVO.step = step;
		}

		//需要更新
		private function needUpdated(type:uint):void{
			updateType = type;
			this.invalidateProperties();
			
			/**
			 * 原来下面这段代码是放在commitProperties()方法中执行
			 * 但是该方法在对组件设置height等属性时也会执行在UserProfileView.mxml和RepostCommentView.mxml
			 * 中有重载组件的updateDisplayList(...)方法，对CustomList设置了height属性，导致该组件的commitProperties()
			 * 方法会被执行多次
			 */ 
			switch(updateType){
				case UPDATE_ALL:
					updateAll();
					break;
				case UPDATE_ONE:
					updateOne();
					break;
				case UPDATE_LIST:
					updateList();
					break;
				case REMOVE_ONE:
					if(removedIndex!=-1){
						removeInstanceAt(removedIndex);
					}
					break;
				case APPEND_LIST:
					appendList();
					break;
			}
			
			//滚动条置顶，追加内容到列表时，不将滚动条置顶
			if(updateType!=APPEND_LIST){
				this.verticalScrollPosition = 0;
			}
			//更新消息背景
			updateBackground();	
			
			this.dispatchEvent(new ClientEvent(ClientEvent.UPDATE_LIST_COMPLETE,true,items.length));
		}
		
		//往列表里添加新消息，在发布微博成功后，直接插入列表中
		public function addNewMsg(msg:Object):void{
			//添加到列表头部
			_dataProvider.addItemAt(msg,0);
			updateCount = 1;
			needUpdated(UPDATE_ONE);
		}
		
		//往列表里添加新消息列表
		private var updateCount:int = 0;
		public function addNewMsgList(msgList:ArrayCollection):void{
			//添加到列表头部
			var tmp:ArrayCollection = new ArrayCollection(msgList.toArray().concat(_dataProvider.toArray()));
			 _dataProvider = tmp;
			updateCount = msgList.length;
			needUpdated(UPDATE_LIST);
		}
		
		//追加数据到列表末尾
		public function appendMsg(msgList:ArrayCollection):void{
			//判断是否为最后一页了，如果取到的数据小于获取的数量，则说明已经是最后一页了
			if(msgList.length<getCount){
				_pageVO.reset();
			}
			
			var tmp:ArrayCollection = new ArrayCollection(_dataProvider.toArray().concat(msgList.toArray()));
			_dataProvider = tmp;
			updateCount = msgList.length;
			needUpdated(APPEND_LIST);
		}
		
		//从列表中删除某条消息
		private var removedIndex:int = -1;
		public function removeMsg(msg:Object):void{
			var index:int = getItemIndex(msg.id);
			trace("deleted index =>"+index+","+msg.id+","+msg.text);
			if(index!=-1){
				removedIndex = index;
				_dataProvider.removeItemAt(index);
				needUpdated(REMOVE_ONE);
				_selectedItem = null;
			}
		}
		
		//删除列表中最后的几条消息，保持列表可容纳的消息数
		private function removeLast():void{
			var cnt:int = items.length - maxCount;
			//如果总数大于列表可容纳的最大数量，则清除不必要的
			if(cnt>0){
				trace("now list length = "+items.length+",need remove "+cnt);
				//删除掉多余的消息
				removeLastMsgs(cnt);
			}
		}
		
		//清除最后N个
		private function removeLastMsgs(count:int):void{
			
			while(count>0){
				//取最后一个
				var item:Object = items.pop();
				this.removeMsg(item.data);
				count--;
			}
		}
		

		//根据ID获取列表中的对象
		public function getItem(id:String):Object{
			for each(var item:Object in _dataProvider){
				if(item.id == id){
					return item;
				}
			}
			return null;
		}
		
		//根据ID获取列表中指定微博索引
		public function getItemIndex(id:String):int{
			for (var i:int =0;i<_dataProvider.length;i++){
				if(String(_dataProvider[i].id) == id){
					return i;
				}
			}
			return -1;
		}
		
		public function get items():Array{
			return container.getChildren();
		}
		
		//清空列表
		public function empty():void{
			container.removeAllChildren();
			_selectedItem = null;
		}
		
		//显示更多面板
		public function startMorePanel():void{
			_isSentRequest = true;
			morePanel.start();
		}
		
		//复位获取更多数据面板
		public function resetMorePanel():void{
			_isSentRequest = false;
			morePanel.stop();
		}
		
		//更新所有的消息为已读
		public function readAll():void{
			for each(var item:MsgManager in items){
				item.read = true;
			}
			updateBackground();
		}
		
		//在私信视图里收到展开私信的消息后，关闭其它已经展开的私信
		private function expandListHandler(event:ClientEvent):void{
			for each(var directMsg:MsgManager in items){
				if(event.data != directMsg){
					directMsg.hideList();
				}
			}
			
			this.selectedItem = event.data;
		}
		
		//打印消息列表
		private function printList(list:ArrayCollection):void{
			for each(var item:Object in list){
				trace(item.id+","+item.text);
			}
		}
		
		
		//快捷键处理
		var verticalPos:Number = 0;
		private function shortCutsHandler(event:KeyboardEvent):void{
			switch(event.keyCode){
				case Keyboard.HOME://列表最上
					verticalPos = 0;
					TweenLite.to(this,0.8,{verticalScrollPosition:verticalPos});
					break;
				case Keyboard.END://列表最下
					verticalPos = this.maxVerticalScrollPosition;
					TweenLite.to(this,0.8,{verticalScrollPosition:verticalPos});
					break;
				case Keyboard.UP:
				case Keyboard.PAGE_UP://列表向上
					verticalPos -= (this.height - 10);
					if(verticalPos<0){
						verticalPos = 0;
					}
					TweenLite.to(this,0.8,{verticalScrollPosition:verticalPos});
					break;
				case Keyboard.DOWN:
				case Keyboard.PAGE_DOWN://列表向下
					verticalPos += (this.height - 10);
					if(verticalPos>this.maxVerticalScrollPosition){
						verticalPos = this.maxVerticalScrollPosition;
					}
					TweenLite.to(this,0.8,{verticalScrollPosition:verticalPos});
					break;
			}
			
			//计算缓动效果的滚动条下一个位置
	       	var start:Number = this.verticalScrollPosition;
			//需要等待下一次获取数据后才能再次发送请求
			getMoreHandler(start,np);			
		}	
		
		/**--------------------------------------- 重载方法 ----------------------------------**/
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
			super.updateDisplayList(unscaledWidth,unscaledHeight);
			//设置滚动条的最小高度，需要使用到 mx_internal 命名空间
			if(this.verticalScrollBar && this.verticalScrollBar.mx_internal::scrollThumb){
				this.verticalScrollBar.mx_internal::scrollThumb.minHeight = THUMB_MIN_HEIGHT;//new CustomScrollThumb();
				this.verticalScrollBar.mx_internal::upArrow.height = 0;
				this.verticalScrollBar.mx_internal::upArrow.visible = false;
				this.verticalScrollBar.mx_internal::upArrow.includeInLayout = false;
				this.verticalScrollBar.mx_internal::downArrow.height = 0;
				this.verticalScrollBar.mx_internal::downArrow.visible = false;
				this.verticalScrollBar.mx_internal::downArrow.includeInLayout = false;
			}

			if(this is Canvas){
				container.width = this.width - 16;
				morePanel.width = this.width - 16;
				morePanel.y = container.y+ container.height;
			}
			
		}
	}
}